#include "key.h"

static const char* TAG = "key_driver";

// 队列：ISR -> gpio_evt_task，gpio_evt_task -> user_event_queue
typedef struct {
    gpio_num_t gpio;
    TickType_t tick;
} gpio_isr_evt_t;



static QueueHandle_t gpio_evt_queue = NULL; //ISR -> gpio_task
static QueueHandle_t key_evt_queue = NULL;  //user event

static key_callback_t s_cb = NULL; //用户回调

// 每个键的状态
typedef struct 
{
    bool      pressed;
    TickType_t last_evt_tick;
    TickType_t press_tick;
} key_state_t;

static key_state_t s_states[KEY_ID_MAX];


// GPIO -> key_id 映射
static bool gpio_to_keyid(gpio_num_t gpio,key_id_t *out_id)
{
    if (gpio == KEY_PIN_PREV)
    {
        *out_id = KEY_ID_PREV;
        return true;
    }

    if (gpio == KEY_PIN_NEXT)
    {
        *out_id = KEY_ID_NEXT;
        return true;
    }

    if (gpio == KEY_PIN_OK)
    {
        *out_id = KEY_ID_OK;
        return true;
    }
    return false;
}

//从 KEY_ID 得到对应GPIO（反向映射，供内部使用）
// static gpio_num_t keyid_to_gpio(key_id_t id)
// {
//     switch (id)
//     {
//         case KEY_ID_PREV:
//             return KEY_PIN_PREV;
//         case KEY_ID_NEXT:
//             return KEY_PIN_NEXT;
//         case KEY_ID_OK:
//             return KEY_PIN_OK;
//         default:
//             return (gpio_num_t)-1;
//     }
// }

// ISR: 只把 gpio + tick 发到队列 (From ISR)
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    gpio_isr_evt_t evt;
    evt.gpio = (gpio_num_t)(intptr_t)arg;
    evt.tick = xTaskGetTickCountFromISR();
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    if(gpio_evt_queue)
    {
        xQueueSendFromISR(gpio_evt_queue, &evt, &xHigherPriorityTaskWoken);
    }
    if(xHigherPriorityTaskWoken){
        portYIELD_FROM_ISR();
    }
}

// gpio processing task：做抖动、按压/释放/点击判定，并把高层事件放到 s_key_evt_queue
static void gpio_evt_task(void* arg)
{
    (void)arg;
    gpio_isr_evt_t intr;
    const TickType_t debounce_ticks = pdMS_TO_TICKS(KEY_DEBOUNCE_MS);
    const TickType_t click_max_ticks = pdMS_TO_TICKS(KEY_CLICK_MAX_MS);

    //初始化状态
    for (int i = 0; i < KEY_ID_MAX; i++)
    {
        s_states[i].pressed = false;
        s_states[i].last_evt_tick = 0;
        s_states[i].press_tick = 0;
    }

    while(1){
        if(xQueueReceive(gpio_evt_queue,&intr,portMAX_DELAY) == pdTRUE){
            key_id_t kid;
            if(!gpio_to_keyid(intr.gpio,&kid)){
                ESP_LOGW(TAG,"Unknown GPIO interrupt: %d",intr.gpio);
                continue;
            }
            //抖动，过滤
            if(intr.tick - s_states[kid].last_evt_tick < debounce_ticks){
                
                // 更新 last_evt_tick 以防止重复快速触发
                s_states[kid].last_evt_tick = intr.tick;
                continue;
            }

            s_states[kid].last_evt_tick = intr.tick;


            // 读取实际电平（active-low 按下为 0）
            int level = gpio_get_level(intr.gpio);
            bool is_pressed = (level == 0); //低电平按下
            
            if(is_pressed && !s_states[kid].pressed){
                //按下事件(边沿下降)
                s_states[kid].pressed = true;
                s_states[kid].press_tick = intr.tick;

                key_event_t kev = {
                    .id = kid,
                    .act = KEY_ACT_PRESS
                };
                
                //发送到用户队列
                xQueueSend(key_evt_queue, &kev, 0);
                if(s_cb){
                    s_cb(&kev);
                }

            }
            else if(!is_pressed && s_states[kid].pressed){
                //释放事件(边沿上升)
                s_states[kid].pressed = false;
                TickType_t press_duration = intr.tick - s_states[kid].press_tick;

                key_event_t kev_release = {
                    .id = kid,
                    .act = KEY_ACT_RELEASE
                };
                //发送释放事件
                xQueueSend(key_evt_queue, &kev_release, 0);
                if(s_cb){
                    s_cb(&kev_release);
                }
                // 如果按下时长在 click 最大值内，视为 click（短按）
                if(press_duration <= click_max_ticks){

                    //点击事件
                    key_event_t kev_click = {
                        .id = kid,
                        .act = KEY_ACT_CLICK
                    };
                    xQueueSend(key_evt_queue, &kev_click, 0);
                    if(s_cb){
                        s_cb(&kev_click);
                    }
                }


            }

        }
    }
    vTaskDelete(NULL);

}

//初始化按键驱动
void keys_init(void)
{
    //创建队列
    if(!gpio_evt_queue){
        gpio_evt_queue = xQueueCreate(10, sizeof(gpio_isr_evt_t));
    }
    if(!key_evt_queue){
        key_evt_queue = xQueueCreate(16, sizeof(key_event_t));
    }

    //配置GPIO
    gpio_config_t io_conf = {
        .pin_bit_mask = ((1ULL<<KEY_PIN_PREV)|(1ULL<<KEY_PIN_NEXT)|(1ULL<<KEY_PIN_OK)),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_ANYEDGE
    };
    gpio_config(&io_conf);

    //安装ISR服务
    gpio_install_isr_service(0);//默认中断分配
    //添加ISR处理函数
    gpio_isr_handler_add(KEY_PIN_PREV, gpio_isr_handler, (void*)(intptr_t)KEY_PIN_PREV);
    gpio_isr_handler_add(KEY_PIN_NEXT, gpio_isr_handler, (void*)(intptr_t)KEY_PIN_NEXT);
    gpio_isr_handler_add(KEY_PIN_OK,   gpio_isr_handler, (void*)(intptr_t)KEY_PIN_OK);

    //启动 gpio_evt_task 任务
    BaseType_t ret = xTaskCreate(gpio_evt_task, "gpio_evt_task", 2048, NULL, 10, NULL);
    if(ret != pdPASS){
        ESP_LOGE(TAG,"Failed to create gpio_evt_task");
    }else{
        ESP_LOGI(TAG, "Key driver initialized (prev=%d next=%d ok=%d)",
                 KEY_PIN_PREV, KEY_PIN_NEXT, KEY_PIN_OK);
    }
}


// 从用户队列取事件
bool key_get_event(key_event_t *out_evt, TickType_t timeout)
{
    if (!key_evt_queue) return false;
    return xQueueReceive(key_evt_queue, out_evt, timeout) == pdTRUE;
}

// 注册回调（NULL 表示取消）
void key_register_callback(key_callback_t cb)
{
    s_cb = cb;
}

